﻿//#include "../../../src/gear/Configuration.hpp"
#include "../../thirdparty/xpack/json.h"
#include "json.hpp"
#include "modeltest.hpp"
#include <conduit.hpp>
#include <gtest/gtest.h>
#include <iostream>
#include<conduit_relay.h>
#include<conduit_relay.hpp>
#include<fstream>
#include<Configuration.hpp>

using json_t = nlohmann::json;

using namespace conduit;
using namespace relay;


TEST(setNode,setNode) {
  Configuration cfg;
  string v1 = "hellow";
  int v2 = 100;
  double v3 = 2.2;
  char v4 = 'a';

  int* v5 = &v2;


  cfg.setNodeValue("v1", v1);
  cfg.setNodeValue("v2", v2);
  cfg.setNodeValue("v3", v3);
  cfg.setNodeValue("v4", v4);
  cfg.setNodeValue("v5", v5);

  cfg.printNode();

  cout << cfg.getNodeValue<string>("v1") << ":" << v1 << endl;
  cout << cfg.getNodeValue<int>("v2") << ":" << v2<< endl;
  cout << cfg.getNodeValue<double>("v3") << ":" <<v3 << endl;
  cout << cfg.getNodeValue<char>("v4") << ":" << v4<< endl;
  cout << cfg.getNodeValue<int*>("v5") << ":" <<v5 << endl;
  
  EXPECT_EQ(cfg.getNodeValue<string>("v1"), v1);
  EXPECT_EQ(cfg.getNodeValue<int>("v2"), v2);
  EXPECT_EQ(cfg.getNodeValue<double>("v3"), v3);
  EXPECT_EQ(cfg.getNodeValue<char>("v4"), v4);
  EXPECT_EQ(cfg.getNodeValue<int*>("v5"), v5);

}

TEST(rwFile, rwFile) {
  Configuration n;
  n.readYamlFile("yml", "../../../../yml_test.yml");
  n.printNode();
  n.clearNode();

  n.readYamlFile("json", "../../../../CMakeSettings.json");
  n.printNode();

  n.saveYamlFile("D:\\t.yml");
  fstream _file;
  _file.open("D:\\t.yml", ios::in);
  EXPECT_TRUE(_file);
}

TEST(ymlstr, ymlstr) {
  Configuration cfg;
  cfg.setNodeValue("yml", "{\"set1\": [0,1,2,3,4], \"set2\":[0.0,1.1,2.2,3.3] }", "yaml");
  cfg.printNode();

  cfg.getNodeValue<int>("set1");
}

TEST(ymlt, ymla)
{
  Configuration cfg;
  cfg.setNodeValue("yml", "{\"set1\": [0,1,2,3,4], \"set2\":[0.0,1.1,2.2,3.3] }", "yaml");

  cfg.printNode();

  auto a = cfg.getNodeValueArray<long long>("yml/set1");
  auto b = cfg.getNodeValueArray<double>("yml/set2");

  EXPECT_EQ(a[1], 1);
  EXPECT_EQ(b[3], 3.3);
}

TEST(b, b)
{
  Generator g("{\"a\": [0,1,2,3,4], \"b\":[0.0,1.1,2.2,3.3] }", "yaml");
  Node n(g, true);
  std::cout << n.to_yaml() << std::endl;

  EXPECT_TRUE(n["a"].dtype().is_int64());
  EXPECT_TRUE(n["b"].dtype().is_float64());

  Generator g2("a: [0,-1,2,-3,4]\nb: [0.0,-1.1,2.2,-3.3]\n", "yaml");
  Node n2(g2, true);
  std::cout << n2.to_yaml() << std::endl;

  EXPECT_TRUE(n["a"].dtype().is_int64());
  EXPECT_TRUE(n["b"].dtype().is_float64());

  int64_array a_val = n2["a"].value();
  EXPECT_EQ(a_val[0], 0);
  EXPECT_EQ(a_val[1], -1);
  EXPECT_EQ(a_val[2], 2);
  EXPECT_EQ(a_val[3], -3);
  EXPECT_EQ(a_val[4], 4);

  float64_array b_val = n2["b"].value();
  EXPECT_EQ(b_val[0], 0);
  EXPECT_EQ(b_val[1], -1.1);
  EXPECT_EQ(b_val[2], 2.2);
  EXPECT_EQ(b_val[3], -3.3);
}

TEST(jsonconduit, jsonconduit)
{
  std::string pure_json = "{\"value\": \"\\\"mystring!\\\"\"}";
  CONDUIT_INFO(pure_json);
  Generator g(pure_json, "yaml");
  Node n(g, true);

  std::cout << n.to_yaml() << std::endl;

  EXPECT_EQ(n["value"].dtype().id(), DataType::CHAR8_STR_ID);
  EXPECT_EQ(n["value"].as_string(), "\"mystring!\"");

  // this tests a specific bug conduit 0.2.1 json parsing logic
  std::string pure_json_2 = "{ \"testing\" : \"space_before_colon\"}";
  CONDUIT_INFO(pure_json_2);
  Generator g2(pure_json_2, "yaml");
  Node n2(g2, true);

  std::cout << n2.to_yaml() << std::endl;
}

TEST(jsonhpp, jsonhpp)
{

#pragma region 序列化
  json_t j;
  j["age"] = 21;               // "age":23
  j["name"] = "diyuyi";        // "name":diyuyi
  j["gear"]["suits"] = "2099"; // "gear":{"suits":"2099"}
  j["jobs"] = { "student" };   // "jobs":["student"]
  std::vector<int> v = { 1, 2, 3 };
  j["numbers"] = v; // "numbers":[1, 2, 3]
  std::map<std::string, int> m = { { "one", 1 }, { "two", 2 } };
  j["map"] = m; // "map":{"one", 1},{"two", 2}

  // 序列化得到json文本形式
  std::cout << j.dump() << std::endl;  // 无缩进
  std::cout << j.dump(2) << std::endl; // 缩进两格
#pragma endregion

#pragma region 反序列化Json
  std::string str = R"({"name":"peter","age":23,"married":true})";
  json_t jd;
  try
  {
    jd = json_t::parse(str); // 从字符串反序列化
  }
  catch (std::exception& e)
  {
    std::cout << e.what() << std::endl;
  }
  assert(jd["age"] == 23); // 验证序列化是否正确

#pragma endregion
}

struct User
{
  int id;
  string name;
  vector<int> uv;
  XPACK(O(id, name, uv)); // 添加宏定义XPACK在结构体定义结尾
};

TEST(xpack, json)
{
#pragma region 结构题转Json
  User u;
  u.id = 1;
  u.name = "leon";
  vector<int> v = { 1, 23, 4, 5 };
  u.uv = v;

  string json = xpack::json::encode(u); // 结构体转json
  cout << json << endl;
#pragma endregion

#pragma region 结构体反序列化
  User u2;
  string json2 = " { \"id\" : 9, \"name\" : \"liufei\", \"uv\" : [ 9, 23, 4, 88 ] }";

  xpack::json::decode(json2, u2);
  cout << " id:" << u2.id << " name:" << u2.name << " uv[0]:" << u2.uv[0] << endl;
#pragma endregion
}

TEST(conduitJson, conduitJson)
{
  Configuration cfg;
  string jsonStr = " { \"id\" : 9, \"name\" : \"liufei\", \"uv\" : [ 9, 23, 4, 88 ] }";

  cfg.setNodeValue("jtest", jsonStr, "json");
  cfg.printNode();
}

TEST(ERROR, ERROR) {

  
 // emit an example info message
  CONDUIT_INFO("An info message");
  Node n;
  n["my_value"].set_float64(42.0);

  // emit an example warning message

  // using "as" for wrong type emits a warning, returns a default value (0.0)
  float32 v = n["my_value"].as_float32();

  // emit an example error message

  try
  {
    // fetching a non-existant path from a const Node emits an error
    const Node& n_my_value = n["my_value"];
    n_my_value["bad"];
  }
  catch (conduit::Error& e)
  {
    // pass
  }
}
